//
// Created by 86150 on 2021/11/12.
//

#include "chatroom.h"
#include<iostream>
#include<cstring>
#include<mutex>

chatroom::chatroom(short P ): self_port(P)
{
	self_sock = socket(PF_INET, SOCK_STREAM, 0);
	if (self_sock == -1)
		error("init fail!");//excption

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(self_port);

	if (bind(self_sock, (sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		error("bind fail");//excption

	if (listen(self_sock, 100) == -1)
		error("listen fail");

	//pthread_mutex_init(&mutx, NULL);
	std::cout<<"mutex is init ok!\n";
	std::cout<<"--------------begin listening----------------\n";
}//initalize the socket
void chatroom::chating_fake()
{
	int N = 0;
	int n = 0;

	while (true)
	{
		sockaddr_in temp_addr;
		socklen_t temp_addr_sz = sizeof(temp_addr);
		char my_buf[20];
		int temp_sock = ::accept(self_sock, (struct sockaddr*)&temp_addr, &temp_addr_sz);
		if (temp_sock == -1)
			error("accept fail!");
		clnt_socks.push_back(temp_sock);

		::read(temp_sock, my_buf, sizeof(my_buf) - sizeof(char));

		if (!strncmp(my_buf, "<chat>", 6)) {
			char user[13];

			for (int i = 0; my_buf[i] != '\0'; i++)
				user[i] = my_buf[i + 6];// read user name

			std::cout<<"user: "<<user<<" ip:"<<temp_addr.sin_addr.s_addr<<" join the chatroom\n";

				std::thread bridge([temp_sock, this, n]() mutable {
					char buf[100];

					while (read(temp_sock, buf, 100) != -1) // get msg from client
						send_all_fake( buf, 100, n);
					// show msg now board
					clnt_socks.erase(clnt_socks.begin() + n);
					close(temp_sock);
				});

				bridge.detach();
		}
		n++;
	}
}//old ver, for terminal, a little complex
void chatroom::on()
{
	sockaddr_in temp_addr;
	socklen_t temp_addr_sz = sizeof(temp_addr);
	char my_buf[20];
	int temp_sock;
	char user[13];

	while (true)
	{
		temp_sock = ::accept(self_sock, (struct sockaddr*)&temp_addr, &temp_addr_sz);
		if (temp_sock == -1)
			error("accept fail!");

		mutex.lock();
		clnt_socks.push_back(temp_sock);
		mutex.unlock();

		::read(temp_sock, my_buf, 20);//judge the kind of service
		mutex.lock();
		for (int i = 0; my_buf[i] != '\0'; i++)
			user[i] = my_buf[i + 6];// read user names
		mutex.unlock();

		if (!strncmp(my_buf, "<chat>", 6)) {
			std::cout<<"user: "<<user/*<<user<<" ip:"<<temp_addr.sin_addr.s_addr*/<<" join the chatroom \n";//<<"socket is: "<<temp_sock<<"\n";
			chating(temp_sock, std::string(user));
		}
		else if(!strncmp(my_buf, "<post>", 6)) {
			mutex.lock();
			int len = clnt_socks.size();
			for (int i = 0; i < len; i++)
				if (clnt_socks[i] == temp_sock)
					clnt_socks.erase(clnt_socks.begin() + i);//clear from list of chaters

			mutex.unlock();

			std::cout<<"user: "<<user<<" post a scripts!\n";
			posting(temp_sock, std::string(user));
		}
		else {
			mutex.lock();
			int len = clnt_socks.size();
			for (int i = 0; i < len; i++)
				if (clnt_socks[i] == temp_sock)
					clnt_socks.erase(clnt_socks.begin() + i);//clear from list of chaters

			mutex.unlock();

			std::cout<<"a html report has been sent\n";
			htmling(temp_sock);//cope the request from browser
		}
	}
}
void chatroom::on2()
{
	/*int clnt_sock;
	sockaddr_in clnt_addr;
	socklen_t clnt_sz;
	char buf[20];
	pthread_t t_id;

	while (true) {
		clnt_sz = sizeof(clnt_addr);
		clnt_sock = ::accept(self_sock, (struct sockaddr*)&clnt_addr, &clnt_sz);

		pthread_mutex_lock(&mutx);
		clnt_socks.push_back(clnt_sock);
		pthread_mutex_unlock(&mutx);

		::read(clnt_sock, buf, 20);

		if (!strncmp(buf, "<chat>", 6)) {
			char user[13];
			for (int i = 0; buf[i] != '\0'; i++)
				user[i] = buf[i + 6];// read user names

			std::cout<<"user: "<<user<<" ip:"<<clnt_addr.sin_addr.s_addr<<" join the chatroom "<<"socket is: "<<clnt_sock<<"\n";
			pthread_create(&t_id, NULL, , (void*)&clnt_sock);
			pthread_detach(t_id);
		}
	}*/
}
void* chatroom::chating2(void* arg)
{
	/*int clnt_sock = *((int*) arg);
	int str_len = 0;
	char msg[100];

	while ((str_len = ::read(clnt_sock, msg, sizeof(msg))) != 0) {
		pthread_mutex_lock(&chatroom::mutx);
		int len = clnt_socks.size();
		for (int i = 0; i < len; i++) {
			write(clnt_socks[i], msg, 100);
		}
		pthread_mutex_unlock(&mutx);
	}

	pthread_mutex_lock(&mutx);
	int size = clnt_socks.size();
	for (int i = 0; i < size; i++)
		if (clnt_sock == clnt_socks[i])
			clnt_socks.erase(clnt_socks.begin());
	pthread_mutex_unlock(&mutx);

	close(clnt_sock);*/
	return NULL;
}
void chatroom::chating(int temp_sock, std::string user)
{
	//std::cout<<"chating's temp_sock is: "<<temp_sock<<"\n";
	mutex.lock();
	db.insert_usr(std::string(user));//insert new usr
	mutex.unlock();
	//debug("dead lock?");
	std::thread bridge([temp_sock, this, user]() {
		char buf[100];
		while (read(temp_sock, buf, 100) != 0) // get msg from client
			send_all(buf, 100);// show msg now board

		std::cout<<"user :"<<user<<" is out \n";
		mutex.lock();
		int len = clnt_socks.size();
		for (int i = 0; i < len; i++)
			if (clnt_socks[i] == temp_sock)
				clnt_socks.erase(clnt_socks.begin() + i);//clear from list of chaters
		mutex.unlock();

		close(temp_sock);
	});

	bridge.detach();
}
void chatroom::posting(int temp_sock, std::string user)
{
	std::thread new_script([temp_sock, user, this]() {
		char buf[40];
		read(temp_sock, buf, 40);

		mutex.lock();
		db.update_usr_cnt(user); //debug(user);
		db.add_srcipt(user, std::string(buf));
		mutex.unlock();

		close(temp_sock);
	});//change the scripts of usr

	new_script.detach();
}
void chatroom::htmling(int temp_sock)
{
	std::string head = "HTTP/1.1 200 OK\r\nAccept-Ranges: bytes\r\n\
					    Content-Length: 300\r\n\
					    Content-Type: text/html;charset=UTF-8\r\n\
					    Connection: on\r\n\r\n";


	if(write(temp_sock, head.c_str(), strlen(head.c_str())) == -1)
		error("html accept fail");

	std::string text = "<!DOCTYPE html>\n"
					   "<meta charset=\"utf-8\">\n"
					   "<html>\n<head>\n"
					   "\t<title>hello page</title>\n"
					   "</head>\n"
					   "<body>\n"
					   "\t欢迎来到校园垃圾识别系统!\n"
					   "\t目前的用户数为" + std::to_string(db.count_all("usr")) +
					   "\n\t目前的垃圾回收记录数为" + std::to_string(db.count_all("recyclist")) +
					   "\n</body>\n"
					   "</html>";

	if (write(temp_sock, text.c_str(), strlen(text.c_str())) == -1)
		error("html send fail");
}
void chatroom::send_all(char* msg, int size)
{
	mutex.lock();
	int len = clnt_socks.size();
	for (int i = 0; i < len; i++)
		write(clnt_socks[i], msg, size);
	mutex.unlock();
}
void chatroom::send_all_fake(char* msg, int size, int n) //show msg for everyone
{
	int i = 0;
	for (auto sock: clnt_socks)
		if (i++ != n)
			write(sock, msg, size - 1);
}
void chatroom::error(std::string info)
{
	std::cout<<"Socket Error: "<<info<<"\n";
	exit(-3);
}